import gnu.io.*;
import java.io.*;
import java.util.*;

import java.awt.image.BufferedImage;
import javax.imageio.*;
import java.io.*;

import java.awt.*;
import javax.swing.JFrame;

public class FrameGrabber
{
	public static void main(String[] args) throws Exception
	{
		if(args.length != 1)
		{
			System.out.println("Usage: java SPOTtoPCTest SPOT_port");
			System.out.println("  ie: java SPOTtoPCTest COM3");
			System.exit(0);
		}
		
		String port = args[0];
		
		CommPortIdentifier SPOTPortID = CommPortIdentifier.getPortIdentifier(port);
		SerialPort SPOTPort = (SerialPort)SPOTPortID.open("SPOTtoPCTest", 2000);
		SPOTPort.disableReceiveThreshold();
		SPOTPort.disableReceiveTimeout();
		SPOTPort.setSerialPortParams(57600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
		
		InputStream in = new SerialInputStream(SPOTPort.getInputStream(), 0);
		DataInputStream din = new DataInputStream(in);
		
		
		int width;
		int height;
		int pixels;
		
		byte[] red;
		byte[] green;
		byte[] blue;
		
		byte[] header = {(byte)0x00, (byte)0x7F, (byte)0xFF};
		byte[] buffer = new byte[3];
		boolean header_found = false;
		
		JFrame frame = new JFrame("CMUCam2");
		
		ShowImage panel = new ShowImage(null);
		frame.getContentPane().add(panel);
		frame.setSize(88*2 + 50, 143 + 50);
		frame.setVisible(true);
		while(true)
		{
			try
				{
				for(int k = 0; k < 3; k++)
					buffer[k] = din.readByte();
				// HAHA! circular buffer
				for(int k = 0; true; k = (k + 1) % 3)
				{
					for(int j = 0; j < 3; j++)
					{
						if(buffer[(k + j) % 3] != header[j])
							break;
						else if(j == 2)
						{
							header_found = true;
						}
					}
					if(header_found == false)
						buffer[k] = din.readByte();
					else
						break;
				}

				
				
				String message = din.readUTF();
				System.out.println("cam: " + message);
				if(message.equals("getting picture"))
				{
					message = din.readUTF();
					System.out.println("cam: " + message);
					if(message.equals("picture received"))
					{
						width = din.readInt();
						height = din.readInt();
						pixels = width * height;
						System.out.println("pc: width: " + width);
						System.out.println("pc: height: " + height);
						System.out.println("pc: pixels: " + pixels);
						red = new byte[pixels];
						green = new byte[pixels];
						blue = new byte[pixels];
						System.out.println("pc: receiving red");
						din.read(red);
						System.out.println("pc: receiving green");
						din.read(green);
						System.out.println("pc: receiving blue");
						din.read(blue);
						
						panel.image = getBImage(width,height, red,green, blue);
						panel.repaint();
					}
				}
			}
			catch(Exception e)
			{
			}
			
		}
	}
	
	private static class ShowImage extends Panel 
	{
		public BufferedImage image = null;
		public ShowImage(BufferedImage image) 
		{
			this.image = image;
		}

		public void paint(Graphics g) 
		{
			if(image != null)
				g.drawImage( image, 0, 0, null);
		}
	}
	
	private static class SerialInputStream extends InputStream
	{
		int timeout;
		InputStream in;
		
		SerialInputStream(InputStream _in, int _timeout)
		{
			in = _in;
			timeout = _timeout;
		}
	
		public int available() throws IOException
		{
			return 1;
		}
	
		public int read() throws IOException
		{
			if(timeout > 0)
			{
				long start = System.currentTimeMillis();
				for(int k = in.read(); (System.currentTimeMillis() - start < timeout); k = in.read())
				{
					if(k != -1)
						return 0xff & k;
				}
			}
			else
			{
				for(int k = in.read(); true; k = in.read())
				{
					if(k != -1)
						return 0xff & k;
				}
			}
			System.out.println("We should not be here in SerialInputStream");
			return 0;
		}
	}
	
	
	
	public static BufferedImage getBImage(int width, int height, byte[] red, byte[] green, byte[] blue) throws IOException
	{	
		BufferedImage image = new BufferedImage(width * 2, height, BufferedImage.TYPE_INT_RGB);
		for(int h = 0; h < height; h++)
		{
			for(int w = 0; w < width * 2; w++)
			{
				// this expects an int for red, green and blue
				// in java, byte order is Most Significant Byte first
				image.setRGB(w, h, (red[h * width + w/2] << 16) +(green[h * width + w/2] << 8) + (blue[h * width + w/2]));
			}
		}
		File output = new File("output.png");  
		ImageIO.write(image, "png", output); 
		return image;
	}
}